#Multiple context-managers in a with-statement
import contextlib
@contextlib.contextmanager
def nest_test(name):
    print('Entering', name)
    yield
    print('Exiting', name)

with nest_test('outer'), nest_test('inner'):
    print('BODY')

with nest_test('outer'):
    with nest_test('inner'):
        print('BODY')


@contextlib.contextmanager
def nest_test(name):
    print('Entering', name)
    yield name
    print('Exiting', name)

with nest_test('outer') as n1, nest_test('inner, nested in ' + n1):
    print('BODY')


#Nested with-statements and exceptions
import contextlib
@contextlib.contextmanager
def propagater(name, propagate):
    try:
        yield
        print(name, 'exited normally.')
    except Exception:
        print(name, 'received an exception!')
    if propagate:
        raise

with propagater('outer', True), propagater('inner', False):
    raise TypeError('Cannot convert lead into gold.')

with propagater('outer', False), propagater('inner', True):
    raise TypeError('Cannot convert lead into gold.')


#Dont pass a collection!
with (nest_test('a'),
      nest_test('b')):
    pass
#seems to work even though it shouldn't????
#It seems to be a 'new' feature????

with nest_test('a'), nest_test('b'):
    pass

#use \ to split over several lines
with nest_test('a'), \
    nest_test('b'), \
    nest_test('c'):
    pass


#Try this instead
with [nest_test('a'),
      nest_test('b')]:
    pass

#or this
with {nest_test('a'),
      nest_test('b')}:
    pass